using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing;
using PlugIn;

namespace MyEditor
{

    class regionsTograph
    {

        int a = 150;//increse 'a' to increase the connection between seed and regions. 
        int[,] oldLab;
        List<Mypoint> Sseed;
        List<Mypoint> Tseed;
        List<node> nodes = new List<node>();
        List<edge> edges = new List<edge>();
        float[] averageColor;
        int[] nodeCount;
        byte[,] ColorGroup;
        int width;
        int height;
        int[] Tlab;
        int[] Slab;
        Bitmap pic;
        int[,] boundary;


        public regionsTograph(int[,] lab, List<Mypoint> Sseed, List<Mypoint> Tseed, byte[,] group, int width, int height,Bitmap pic)
        {
            this.oldLab = lab;
            this.Sseed = Sseed;
            this.Tseed = Tseed;
            this.ColorGroup = group;
            this.width = width;
            this.height = height;
            this.pic = pic;
            CalAverageColor();
            creatSeedRegion();
            doconvert();
            createTlink();
            createSlink();
            
        }

        public List<node> getNodes()
        {
            return nodes;
        }

        public List<edge> getEdges()
        {
            return edges;
        }

        void CalAverageColor()
        {
            int LabCount = 0;
            for (int i = 0; i < width; i++)
                for (int j = 0; j < height; j++)
                {
                    if (oldLab[i, j] > LabCount)
                        LabCount = oldLab[i, j];
                }
            averageColor = new float[LabCount + 1];
            nodeCount = new int[LabCount + 1];
            boundary = new int[LabCount + 1, LabCount + 1];
            for (int i = 0; i < width; i++)
                for (int j = 0; j < height; j++)
                {
                    //int t=(int)Color.FromArgb(0,pic.GetPixel(i,j).R,pic.GetPixel(i,j).G,pic.GetPixel(i,j).B).ToArgb();
                    //averageColor[oldLab[i, j]] = nodeCount[oldLab[i, j]] * (averageColor[oldLab[i, j]] / (nodeCount[oldLab[i, j]] + 1)) + t / (nodeCount[oldLab[i, j]] + 1);
                    averageColor[oldLab[i, j]] = ColorGroup[i, j];
                    nodeCount[oldLab[i, j]]++;

                }
            for (int i = 0; i <= LabCount; i++)
            {
                averageColor[i] = (averageColor[i]/nodeCount[i]);
            }
            
        }

        void doconvert()
        {
            for (int i = 2; i < width - 2; i++)
                for (int j = 2; j < height - 2; j++)
                {
                    if (oldLab[i, j] == 0)
                    {
                        if ((oldLab[i - 2, j] != oldLab[i + 2, j]) && oldLab[i - 2, j] != 0 && oldLab[i + 2, j] != 0)
                        {
                            boundary[oldLab[i - 2, j], oldLab[i + 2, j]]++;
                            boundary[oldLab[i + 2, j], oldLab[i - 2, j]]++;
                        }
                    }
                }

            for (int j = 2; j < height - 2; j++)
                for (int i = 2; i < width - 2; i++)
                {
                    if (oldLab[i, j] == 0)
                    {
                        if ((oldLab[i, j - 2] != oldLab[i, j + 2]) && oldLab[i, j - 2] != 0 && oldLab[i, j + 2] != 0)
                        {
                            boundary[oldLab[i, j - 2], oldLab[i, j + 2]]++;
                            boundary[oldLab[i, j + 2], oldLab[i, j - 2]]++;
                        }
                    }
                }



            for (int i = 2; i < width - 2; i++)
                for (int j = 2; j < height - 2; j++)
                {
                    if (oldLab[i, j] == 0)
                    {
                        if ((oldLab[i - 2, j] != oldLab[i + 2, j]) && oldLab[i - 2, j] != 0 && oldLab[i + 2, j] != 0)
                        {

                            node p = new node();
                            p.name = oldLab[i - 2, j];

                            bool has = false;
                            foreach (node t in nodes)
                            {
                                if (t.Equals(p))
                                    has = true;
                            }
                            if (!has)
                                nodes.Add(p);

                            node p2 = new node();
                            p2.name = oldLab[i + 2, j];

                            has = false;
                            foreach (node t in nodes)
                            {
                                if (t.Equals(p2))
                                    has = true;
                            }
                            if (!has)
                                nodes.Add(p2);

                            edge e = new edge();
                            e.terminal1 = p;
                            e.terminal2 = p2;
                            float dist = (averageColor[oldLab[i - 2, j]]) - (averageColor[oldLab[i + 2, j]]);
                            if (dist < 0)
                                dist = 0 - dist;
                            e.capacity = a * (1 / ((dist * dist) + 1)) * boundary[oldLab[i - 2, j], oldLab[i + 2, j]];
                            bool has2 = false;
                            foreach (edge te in edges)
                            {
                                if (te.Equals(e))
                                    has2 = true;
                            }
                            if (!has2)
                                edges.Add(e);
                        }
                    }
                }
            for (int j = 2; j < height - 2; j++)
                for (int i = 2; i < width - 2; i++)
                {
                    if (oldLab[i, j] == 0)
                    {
                        if ((oldLab[i, j - 2] != oldLab[i, j + 2]) && oldLab[i, j - 2] != 0 && oldLab[i, j + 2] != 0)
                        {

                            node p = new node();
                            p.name = oldLab[i, j - 2];
                            bool has = false;
                            foreach (node t in nodes)
                            {
                                if (t.Equals(p))
                                    has = true;
                            }
                            if (!has)
                                nodes.Add(p);
                            node p2 = new node();
                            p2.name = oldLab[i, j + 2];
                            has = false;
                            foreach (node t in nodes)
                            {
                                if (t.Equals(p2))
                                    has = true;
                            }
                            if (!has)
                                nodes.Add(p2);
                            edge e = new edge();
                            e.terminal1 = p;
                            e.terminal2 = p2;
                            float dist = ((averageColor[oldLab[i, j - 2]]) - (averageColor[oldLab[i, j + 2]]));
                            if (dist < 0)
                                dist = 0 - dist;
                            e.capacity = a * (1 / ((dist * dist) + 1)) * boundary[oldLab[i, j - 2], oldLab[i, j + 2]];
                            bool has2 = false;
                            foreach (edge te in edges)
                            {
                                if (te.Equals(e))
                                    has2 = true;
                            }
                            if (!has2)
                                edges.Add(e);
                        }
                    }
                }


        }

        void creatSeedRegion()
        {
            Tlab = new int[Tseed.Count];
            for (int j = 0; j < Tseed.Count; j++)
            {
                Tlab[j] = -9999;
            }

            int i = 0;
            foreach (Mypoint p in Tseed)
            {
                int k;
                for (k = 0; k < i; k++)
                {
                    if (Tlab[k] == oldLab[p.x, p.y])
                    {
                        break;
                    }
                }
                if (k == i)
                {
                   
                    Tlab[i] = oldLab[p.x, p.y]; 
                    i++;
                }

            }


            Slab = new int[Sseed.Count];
            for (int j = 0; j < Sseed.Count; j++)
            {
                Slab[j] = -9999;
            }

            i = 0;
            foreach (Mypoint p in Sseed)
            {
                int k;
                for (k = 0; k < i; k++)
                {
                    if (Slab[k] == oldLab[p.x, p.y])
                    {
                        break;
                    }
                }
                if (k == i)
                {
                    
                    Slab[i] = oldLab[p.x, p.y];
                    i++;
                }

            }

            i=0;
            while (i<Sseed.Count)
            {
                if (Slab[i] == -9999)
                    break;
                int j = 0;
                while (j<Tseed.Count)
                {
                    if (Tlab[j] == -9999)
                        break;
                    if (Slab[i] == Tlab[j])
                    {
                        /*for (int k = i; k < Sseed.Count; k++) //if a region is in both Sseed and Tseed, only put it in the Sseed
                        {
                            if (k < Sseed.Count - 1)
                                Slab[k] = Slab[k + 1];
                        }
                        Slab[Sseed.Count-1] = -9999;*/
                        for (int k = i; k < Tseed.Count; k++)
                            if (k < Tseed.Count - 1)
                            Tlab[k] = Tlab[k + 1];
                        Tlab[Tseed.Count-1] = -9999;
                    }
                    j++;
                }

                i++;
            }
        }

        void createTlink()
        {
            node T = new node();
            T.name = -2000;
            T.tree = 2;
           
            foreach (node p in nodes)
            { 
                bool SeedofT = false;
                bool SeedofS = false;
                foreach (int lab in Tlab)
                {
                    if (lab == p.name)
                    {
                        SeedofT = true;
                        break;
                    }

                }

                foreach (int lab in Slab)
                {
                    if (lab == p.name)
                    {
                        SeedofS = true;
                        break;
                    }

                }


                if (SeedofT &&(!SeedofS))
                {
                    edge e = new edge();
                    e.terminal2 = p;
                    e.terminal1 = T;
                    e.capacity = int.MaxValue;
                    edges.Add(e);
                }

                if ((!SeedofT) && (!SeedofS))
                {
                    edge e = new edge();
                    e.terminal2 = p;
                    e.terminal1 = T;
                    float ds = minScolor(p);
                    float dt = minTcolor(p);
                    e.capacity = dt / (ds + dt);
                    edges.Add(e);
                }
            }
        }

        void createSlink()
        {
            node S = new node();
            S.name = -1000;
            S.tree = 1;
            
            foreach (node p in nodes)
            {
                bool SeedofT = false;
                bool SeedofS = false;
                foreach (int lab in Tlab)
                {
                    if (lab == p.name)
                    {
                        SeedofT = true;
                        break;
                    }

                }

                foreach (int lab in Slab)
                {
                    if (lab == p.name)
                    {
                        SeedofS = true;
                        break;
                    }

                }


                if (SeedofS && (!SeedofT))
                {
                    edge e = new edge();
                    e.terminal2 = p;
                    e.terminal1 = S;
                    e.capacity = int.MaxValue;
                    edges.Add(e);
                }

                if ((!SeedofT) && (!SeedofS))
                {
                    edge e = new edge();
                    e.terminal2 = p;
                    e.terminal1 = S;
                    float ds = minScolor(p);
                    float dt = minTcolor(p);
                    e.capacity = ds / (ds + dt);
                    edges.Add(e);

                }
            }
        }

        float minTcolor(node p)
        {
            float min = int.MaxValue;
            foreach (int lab in Tlab)
            {
                if (lab > 0)
                {
                    float dist = (averageColor[p.name] - averageColor[lab]);
                    if (dist < 0)
                        dist = 0 - dist;
                    if (dist < min)
                    {
                        min = dist;
                    }
                }
            }
            return min;
        }

        float minScolor(node p)
        {
            float min = int.MaxValue;
            foreach (int lab in Slab)
            {
                if (lab > 0)
                {
                    float dist = (averageColor[p.name] - averageColor[lab]);
                    if (dist < 0)
                        dist = 0 - dist;
                    if (dist < min)
                    {
                        min = dist;
                    }
                }
            }
            return min;
        }

    }




}
